package com.cjyd.hrjb.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cjyd.hrjb.exception.ServiceException;
import com.cjyd.hrjb.mapper.UserMapper;
import com.cjyd.hrjb.model.dto.ResponseDto;
import com.cjyd.hrjb.model.dto.TokenDto;
import com.cjyd.hrjb.model.dto.UserDto;
import com.cjyd.hrjb.model.dto.XetUser;
import com.cjyd.hrjb.model.entity.User;
import com.cjyd.hrjb.model.enums.UserSync;
import com.cjyd.hrjb.model.vo.UserVo;
import com.cjyd.hrjb.service.AccessTokenService;
import com.cjyd.hrjb.service.UserService;
import com.cjyd.hrjb.utils.ResultCode;
import com.cjyd.hrjb.utils.XetUserUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * Created fei wo by 2020/4/6
 */
@Slf4j
@Service
public class UserServiceImpl implements UserService {

    private static final String XET_USER_REGISTER_URL = "https://api.xiaoe-tech.com/xe.user.register/1.0.0";
    private static final String XET_GET_USER_INFO = "https://api.xiaoe-tech.com/xe.user.info.get/1.0.0";
    private final ObjectMapper objectMapper = new ObjectMapper();

    private final UserMapper userMapper;
    private final AccessTokenService accessTokenService;

    public UserServiceImpl(UserMapper userMapper, AccessTokenService accessTokenService) {
        this.userMapper = userMapper;
        this.accessTokenService = accessTokenService;
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public UserVo register(UserDto userDto) {
        if (StringUtils.isEmpty(userDto.getWxUnionId()) && StringUtils.isEmpty(userDto.getPhone())) {
            throw new ServiceException(ResultCode.UNION_ID_OR_PHONE_EMPTY);
        }
        User user = new User();
        BeanUtils.copyProperties(userDto, user);
        int insert = userMapper.insert(user);
        if (insert != 1) throw new ServiceException(ResultCode.USER_REGISTER_FAIL);
        // 存在推荐人，更新推荐人信息
        if (userDto.getRecommendId() != null) {
            updateRecommendUserInfo(user);
        }
        // 同步小鹅通
        XetUser xetUser = syncXetUser(userDto);
        if (xetUser != null) {
            user.setUserId(xetUser.getUserId());
            user.setSync(UserSync.SYNCED);
            // 更新用户信息
            int update = userMapper.updateById(user);
            if (update != 1) throw new ServiceException(ResultCode.USER_REGISTER_FAIL);
        }
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);

        return userVo;
    }

    /**
     * 更新推荐人信息
     * @param currentUser 当前用户
     */
    private void updateRecommendUserInfo(User currentUser) {
        User user = userMapper.selectById(currentUser.getRecommendId());
        if (user == null) {
            log.warn("【{}用户的推荐人不存在】",StringUtils.isEmpty(currentUser.getPhone()) ? currentUser.getWxUnionId():currentUser.getPhone());
            return;
        }
        String layer = user.getLayer();
        if (StringUtils.isEmpty(layer)) {
            layer = String.valueOf(currentUser.getId());
        }else {
            layer = layer+"_"+currentUser.getId();
        }
        user.setLayer(layer);
        int update = userMapper.updateById(user);
        if (update != 1) throw new ServiceException(ResultCode.USER_REGISTER_FAIL);
    }

    /**
     * 同步用户信息到小鹅通
     * @param userDto {@link UserDto}
     */
    private XetUser syncXetUser(UserDto userDto) {
        TokenDto tokenDto = accessTokenService.get();
        Map<String, Object> params = null;
        String body = null;
        try {
            params = XetUserUtil.buildRegUserParams(tokenDto.getAccessToken(), userDto, "recommendId");
        } catch (IllegalAccessException e) {
            throw new ServiceException(ResultCode.PARAMS_INVALID.setMsg(e.getMessage()));
        }
        try {
            body = objectMapper.writeValueAsString(params);
        } catch (JsonProcessingException e) {
            throw new ServiceException(ResultCode.PARAMS_INVALID);
        }
        log.info("【同步小鹅通请求json】 ===> {}",body);
        if (body != null) {
            String respStr = HttpUtil.post(XET_USER_REGISTER_URL, body);
            ResponseDto<XetUser> xetUserResponseDto = null;
            try {
                xetUserResponseDto = JSONUtil.toBean(respStr, new TypeReference<ResponseDto<XetUser>>() {
                }, false);
            }catch (Exception e) {
                throw new ServiceException(ResultCode.USER_REGISTER_FAIL);
            }
            log.info("【同步小鹅通返回结果】===> {}", xetUserResponseDto);
            if (xetUserResponseDto != null) {
                Integer code = xetUserResponseDto.getCode();
                switch (code) {
                    case 2501:
                        throw new ServiceException(ResultCode.UNION_ID_OR_PHONE_EMPTY);
                    case 2502:
                        throw new ServiceException(ResultCode.PARAMS_INVALID.setMsg(xetUserResponseDto.getMsg()));
                    case 2504:
                        throw new ServiceException(ResultCode.USER_PHONE_EXISTS);
                }
                return xetUserResponseDto.getData();
            }
        }
        return null;
    }

    @Override
    public UserVo syncXetUserInfo(Long userId) {
        User user = userMapper.selectById(userId);
        if (user == null) throw new ServiceException(ResultCode.USER_NOT_EXISTS);
        TokenDto tokenDto = accessTokenService.get();
        Map<String, Object> params = XetUserUtil.buildGetUserInfoParams(tokenDto.getAccessToken(), user.getUserId(), "recommendId","layer","sync","email");
        try {
            String body = objectMapper.writeValueAsString(params);
            log.info("【获取小鹅通用户信息请求参数】 ===> {}",body);
            String respStr = HttpUtil.post(XET_GET_USER_INFO, body);
            ResponseDto<User> userResponseDto = JSONUtil.toBean(respStr, new TypeReference<ResponseDto<User>>() {
            }, true);
            log.info("【获取小鹅通用户信息数据】 ===> {}",respStr);
            if (userResponseDto.getCode() == 0) {
                UserVo userVo = new UserVo();
                User data = userResponseDto.getData();
                BeanUtils.copyProperties(data, user, "recommendId","sync","id","userId");
                int update = userMapper.updateById(user);
                if (update != 1) {
                    log.warn("【更新用户信息失败】");
                }
                BeanUtils.copyProperties(data, userVo);
                return userVo;
            }else {
                throw new ServiceException(ResultCode.SYNC_USER_INFO_FAIL);
            }
        } catch (JsonProcessingException e) {
            throw new ServiceException(ResultCode.PARAMS_INVALID.setMsg(e.getMessage()));
        }
    }

    @Override
    public UserVo getRecommendUserInfo(Long userId) {
        User user = userMapper.selectById(userId);
        UserVo userVo = new UserVo();
        if (user == null) throw new ServiceException(ResultCode.USER_NOT_EXISTS);
        Long recommendId = user.getRecommendId();
        User recommendUser = userMapper.selectById(recommendId);
        if (recommendUser == null) throw new ServiceException(ResultCode.RECOMMEND_USER_NOT_EXISTS);
        BeanUtils.copyProperties(recommendUser, userVo);
        return userVo;
    }

    @Override
    public IPage<UserVo> getSubUserPageList(Long userId, Integer offset, Integer limit) {
        User user = userMapper.selectById(userId);
        if (user == null) throw new ServiceException(ResultCode.USER_NOT_EXISTS);
        String layer = user.getLayer();
        if (StringUtils.isEmpty(layer)) {
            return null;
        }
        String[] split = layer.split("_");
        List<String> subIds = Arrays.asList(split);
        List<String> pageIds = CollUtil.page(offset, limit, subIds);
        List<User> users = userMapper.selectBatchIds(pageIds);
        List<UserVo> userVos = new ArrayList<>();
        users.forEach(u -> {
            UserVo userVo = new UserVo();
            BeanUtils.copyProperties(u, userVo);
            userVos.add(userVo);
        });
        Page<UserVo> userVoPage = new Page<>();
        userVoPage.setTotal(subIds.size());
        userVoPage.setCurrent(offset);
        userVoPage.setRecords(userVos);
        return userVoPage;
    }

    @Override
    public IPage<UserVo> listPage(String searchKey, Integer offset, Integer limit) {
        LambdaQueryWrapper<User> queryWrapper = Wrappers.<User>lambdaQuery()
                .like(!StringUtils.isEmpty(searchKey), User::getPhone, searchKey)
                .like(!StringUtils.isEmpty(searchKey), User::getNickname, searchKey)
                .like(!StringUtils.isEmpty(searchKey), User::getName, searchKey)
                .orderByDesc(User::getCreatedAt);
        Page<User> userPage = new Page<>(offset, limit);
        Page<User> selectPage = userMapper.selectPage(userPage, queryWrapper);
        Page<UserVo> userVoPage = new Page<>();
        BeanUtils.copyProperties(selectPage, userVoPage);
        List<UserVo> userVos = new ArrayList<>();
        selectPage.getRecords().forEach(user -> {
            UserVo userVo = new UserVo();
            BeanUtils.copyProperties(user, userVo);
            userVos.add(userVo);
        });
        userVoPage.setRecords(userVos);
        return userVoPage;
    }
}
